package yun.web.springmvc;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSONArray;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerExecutionChain;
import yun.web.activerecord.dialect.ARP;
import yun.web.enjoy.kit.PluginKit;
import yun.web.enjoy.template.Engine;
import yun.web.springmvc.ext.MvcWriteUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;

public class MvcDispatchServlet extends DispatcherServlet {

    @Override
    public void destroy() {
        // 销毁spring上下文对象
        WebApplicationContext webApplicationContext = getWebApplicationContext();
        ((AnnotationConfigWebApplicationContext) webApplicationContext).close();

        // 清理engine
        Engine.remove("spring-mvc");
        Engine.remove("cache-engine");

        // 清理Plguin
        PluginKit.getPluginList().forEach(it -> it.stop());
        PluginKit.getPluginList().clear();

        super.destroy();
        System.gc();
    }

    boolean devMode = null == System.getProperty("devMode");

    Log log = LogFactory.get("MvcDispatchServlet");

    public MvcDispatchServlet() throws Exception {


        log.info(devMode ? "=== 目前处于开发者模式" : "=== 目前处于生产模式");

        //创建默认引擎, 用在html模板渲染
        Engine.create("spring-mvc").setDevMode(devMode)
                // 不设置为ClassPathResource, 配置maven resource标签,
                // 无论开发模式还是生产模式都从WorkDirectory文件, 而不是操蛋的ClassPath
                .setBaseTemplatePath("webapp/WEB-INF");

        //创建默认引擎, 用在缓存
        Engine.create("cache-engine").setDevMode(devMode);

        //加载配置
        YunConfigurableEnvironment env = new YunConfigurableEnvironment();

        // 初始化数据源
        JSONArray datasource = env.getJSONArray("datasource");// List<LinkedHashMap>
        if (datasource != null) {
            ARP.init(datasource);
        }

        // spring扫描包路径
        String scanPackages = "yun.web," + env.getProperty("scanPackages", "");
        AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext();
        webApplicationContext.setConfigLocation(scanPackages);
        webApplicationContext.setEnvironment(env);
        setApplicationContext(webApplicationContext);
        setDispatchOptionsRequest(true);
    }


    @Override
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;

        // 获取合适的handler
        HandlerExecutionChain mappedHandler = null;
        try {
            mappedHandler = getHandler(processedRequest);
        } catch (Exception e) {
            log.error(e);
            response.setStatus(404);
            return;
        }

        // 没有合适的handler
        if (mappedHandler == null) {

            //
            try {

                // 从resourceDir读取文件
                File file = getFile(request.getRequestURI());
                if (file != null) {
                    MvcWriteUtil.writeStatic(request, response, file);
                }
                // springmvc404, 同时也没有相应文件,
                else {
                    // 获取404处理器
                    try {
                        NotFoundExceptionHandlerItf notFoundExceptionHandler = getWebApplicationContext().getBean(NotFoundExceptionHandlerItf.class);
                        // 拿到了不为null
                        if (notFoundExceptionHandler != null) {
                            noHandlerFound(processedRequest, response);
                        } else {
                            notFoundExceptionHandler.handleException(request, response);
                        }
                    }
                    // 拿不到
                    catch (Exception e) {
                        noHandlerFound(processedRequest, response);

                    }
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            }
            return;
        }

        // Determine handler adapter for the current request.
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

        // Process last-modified header, if supported by the handler.
       /*
        String method = request.getMethod();
        boolean isGet = "GET".equals(method);
        if (isGet || "HEAD".equals(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                return;
            }
        }
        */

        // Actually invoke the handler.
        ha.handle(processedRequest, response, mappedHandler.getHandler());

    }

    public File getFile(String path) {
        // 不能直接访问web-inf
        if (path.toLowerCase().contains("web-inf")) return null;

      /*  // 资源目录
        String[] resourceDirs = {"webapp", "src/main/WebRoot", "webapp", "WebRoot"};

        for (String resourceDir : resourceDirs) {
            File file = new File(resourceDir, path);
            // 必须是文件而非目录
            if (file.exists() && file.isFile()) return file;
        }*/
        File file = new File("webapp", path);
        // 必须是文件而非目录
        return file.isFile() ? file : null;
    }

}
